# -*- coding: utf-8 -*-
import os.path

print('开始1')
from universal.root_path import init_log
print('开始2')
try:
    from Module.MainWindow.action_tools import action_tool
    print('a1')
    from Module.MainWindow.Splash import *
    from mylibs.version import __version__
    from Module.MainWindow.WindowMix import WindowMixin
    from mylibs.zoomWidget import ZoomWidget
    print('导入库完成')
    __appname__ = '章鱼博士'
except Exception as e:
    from Module.xRayDetection.xray.logs import Logger
    print(str(e))
    init = init_log()
    init.log(Logger.ERROR, str(e), exception=True)

from cryptography.fernet import Fernet
from datetime import datetime
class LicenseValidator:
    def __init__(self, license_path, key_path):
        self.license_path = license_path
        self.key_path = key_path

    def is_license_valid(self):
        try:
            # 读取密钥和许可证
            with open(self.key_path, 'rb') as key_file:
                key = key_file.read()
            cipher_suite = Fernet(key)
            
            with open(self.license_path, 'rb') as lic_file:
                encrypted_license = lic_file.read()
            
            # 解密许可证
            decrypted_license = cipher_suite.decrypt(encrypted_license).decode()
            license_info = eval(decrypted_license)
            
            # 验证授权信息
            expiration_date = datetime.strptime(license_info['expiration_date'], '%Y-%m-%d %H:%M:%S')
            if expiration_date < datetime.now() or not license_info['is_valid']:
                return False
            return True
        except Exception as e:
            print(f"An error occurred: {e}")
            return False

# MainWindow
class MainWindow(QMainWindow, WindowMixin):
    FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = list(range(3))
    def __init__(self):
        self.logger = init_log()
        try:
            self.mainWindow_ = MainWindow_(self)   #初始化打开选择工程界面
            self.mainWindow_.show()
            self.mainWindow_.setWindowModality(Qt.ApplicationModal)  # 禁用主窗口
            super(MainWindow, self).__init__()
            self.Init_parameter()  #初始化参数

            self.setWindowTitle(__appname__)
            self.setStyleSheet("background-color:rgb(30,40,75)")

            self.settings = Settings()  #加载Labelimg的PKL
            self.settings.load()

            #-----widget-----
            self.ModelPage()  # 设置左侧Tab选择界面模式
            self.codeWidget_ = codeWidget("main")  # 退出密码部分
            self.codeWidget_.exit_Odvision.connect(self.exit_OD)

            self.mainWindow_slider = MainWindow_slider()  #调整线条粗细界面
            self.CanvasPart()   #画布部分
            self.ModelExport()    #判断是否导入相应模块
            self.InitLabelimg()     #LabelImg的初始化

            self.actionTool = action_tool(self)  # Actions工具条
            self.labelpageAction,self.trainpageAction,self.testpageAction,self.FTPpageAction, self.Industry_model,\
            self.D3DpageAction,self.ClassicalAction,self.actions,self.edit, self.delete = self.actionTool.GetAction()

            self.ModelTools()   # 界面模块工具条
            self.X_ray_page = XrayClass(self)  #Xray工具条部分
            self.AutoLogin()  #自动登录上传部分
            self.Tray()  #创建托盘

        except Exception as e:
            print("错误信息：",str(e))
            self.logger.log(Logger.ERROR, str(e), exception=True)

    def Tray(self):
        self.tray = QSystemTrayIcon(self)  # 创建系统托盘对象
        self.icon = QIcon(":/icons/1-2")
        self.tray.setIcon(self.icon)
        # self.tray.activated.connect(self.TuoPanEvent)  # 设置托盘点击事件处理函数
        self.tray_menu = QMenu(QApplication.desktop())  # 创建菜单
        self.RestoreAction = QAction(u'还原 ', self, triggered=self.show)  # 添加一级菜单动作选项(还原主窗口)
        self.QuitAction = QAction(u'退出 ', self, triggered=self.quit)  # 添加一级菜单动作选项(退出程序)
        self.tray_menu.addAction(self.RestoreAction)  # 为菜单添加动作
        self.tray_menu.addAction(self.QuitAction)
        self.tray.setContextMenu(self.tray_menu)  # 设置
        self.tray.show()

    def ModelPage(self):  # 模式界面选择
        self.labelLayouContainer = self.LabelTab()  # Tab1
        self.videoWidget = Video(self)
        EnhanceList = self.ImgEnhance()  # Tab3
        Format_conversion = self.FormatTrans()  # Tab4  #xml转txt,格式转换

        self.leftwidget = TabWidget([self.labelLayouContainer, self.videoWidget, EnhanceList,Format_conversion], ["标注", "播放", "数据增强","格式转换"])
        self.leftwidget.currentChanged.connect(self.tabChanged)

    def Init_parameter(self):
        # 工程信息
        self.filePath = None
        self.projectTask = ''
        self.projectPath = ''
        self.labelFlag = False
        self.labelImgsPath = ''
        self.usingPascalVocFormat = True
        self.usingYoloFormat = False

        self.mImgList = []
        self.labelClasses = []
        self.compressPicPath_ = []  # 输入搜索后新建的列表
        self.ini_ = 1
        self.main = queue.Queue()
        from collections import defaultdict
        self.nameDict = defaultdict(list) #类别字典
        self.mask = False
        self.itemsToShapes = {}
        self.shapesToItems = {}
        self.prevLabelText = ''
        self.save_status = 0
        # ------LabelImg↓----------
        self.dirty = False
        self._noSelectionSlot = False
        self._beginner = True
        self.screencastViewer = self.getAvailableScreencastViewer()
        self.screencast = "https://youtu.be/p0nR2YsCY_U"
        self.labelDialog = LabelDialog(parent=self, listItem=self.labelClasses)  #
        print('加载参数完成')

    def LabelTab(self):  #Tab的标注
        self.Tablabel = LabelTab(self)
        self.labelList ,self.dock,self.fileListWidget, self.TextBrowser,self.Upload= self.Tablabel.returnParameter()
        self.Upload.clicked.connect(self.Upload_)
        return self.Tablabel.labelLayouContainer

    def ModelTools(self):  #判断是否要加入模块
        self.daohangActions = []
        ToolsDaohang = []
        def AddDaohang(page,status,pageAction,Industry=False):
            if ODModule_config.read_value(page, status) == "1":
                self.daohangActions.append(pageAction)
                if Industry != True:
                    ToolsDaohang.append(pageAction)

        AddDaohang('Label_Tools', 'page',self.labelpageAction)
        AddDaohang('TrainAndTest', 'page',self.trainpageAction)
        AddDaohang('TrainAndTest', 'page',self.testpageAction)
        AddDaohang('FTP', 'page',self.FTPpageAction)
        AddDaohang('Industry', 'page', self.Industry_model,True)
        AddDaohang('ThreeD', 'page',self.D3DpageAction)
        AddDaohang('Classical', 'page',self.ClassicalAction)

        self.toolsdaohang = self.toolbar('daohangTools', None, Qt.TopToolBarArea)
        addActions(self.toolsdaohang, ToolsDaohang)

    def AutoLogin(self):   #------自动登录FTP上传------
        if ODModule_config.read_value('FTP', 'page') == "1":
            if self.FTPWidget.pageS_.AutoLoginBox != None:
                if self.FTPWidget.pageS_.AutoLoginBox.isChecked():
                    self.mainWindow_.txtWidget.setCurrentRow(0)
                    self.mainWindow_.choseRecentProject(self.mainWindow_.txtWidget.currentItem())
                    self.FTPWidget.pageS_.Login_Thread()
                    self.FTPWidget.pageS_.setCurrentIndex(1)
                    time.sleep(2)
                    self.FTPWidget.pageS_.Tab4_Upload_function()

    def Stack_widget(self,widegt, MODEL=True):
        if MODEL:
            self.stack.addWidget(widegt)  #
        DockWidget = ADD_DOCK_lEFT(self.addDockWidget,widegt.leftwidget)
        self.AllDockWdiget.append(DockWidget)
        return DockWidget

    def ModelExport(self):  #判断是否导入模块
        try:
            self.stack = QStackedLayout(self)  # 页面
            self.stack.addWidget(self.canvas)
            self.AllDockWdiget = []
            self.MainWidget3d = None

            self.labelDockWidget = self.Stack_widget(self, False)
            self.labelDockWidget.setObjectName("labelDockWidget")

            if ODModule_config.read_value('Industry', 'page') == "1":
                from Module.IndustryModel.IndustryWidget import IndustryWidget_
                self.IndustryWidget = IndustryWidget_()
                self.IndustryDockWidget = self.Stack_widget(self.IndustryWidget, True)
                self.IndustryDockWidget.setObjectName("IndustryDockWidget")

            if ODModule_config.read_value('TrainAndTest', 'page') == "1":
                from Module.TrainAndTest.TrainStackWidget import trainWidget
                from Module.TrainAndTest.TestStackWidget import TestWidget
                self.trainWidget = trainWidget()
                thd1.join()
                Find_Device(self.trainWidget.selectDevice, thd1.device_list)
                self.testWidget = TestWidget()
                Find_Device(self.testWidget.selectDevice, thd1.device_list)
                self.TrainDockWidget = self.Stack_widget(self.trainWidget, True)
                self.TrainDockWidget.setObjectName("TrainDockWidget")
                self.TestDockWidget = self.Stack_widget(self.testWidget, True)
                self.TestDockWidget.setObjectName("TrainDockWidget")

            if ODModule_config.read_value('FTP', 'page') == "1":
                self.FTPWidget = MainWindow_FTP()
                self.FTPDockWidget = self.Stack_widget(self.FTPWidget, True)
                self.FTPDockWidget.setObjectName("FTPDockWidget")
                if ODModule_config.read_value('FTP', 'tab2') == "1":
                    Find_Device(self.FTPWidget.pageS_.combox, thd1.device_list)

            if ODModule_config.read_value('Classical', 'page') == "1":
                from Module.classical.main import MyApp
                self.Classical_cv = MyApp()
                self.ClassicalDock = self.Stack_widget(self.Classical_cv, True)
                self.ClassicalDock.setObjectName("ClassicalDock")

            self.scrollArea.setLayout(self.stack)
            self.setContextMenuPolicy(Qt.NoContextMenu)  # 关闭右键显示TOOlbar
        except Exception as e:
            print(str(e))


    def exit_OD(self):
        self.codeWidget_.exit()
        self.deleteLater()

    def ImgEnhance(self):
        name_list = ["图像&标签原路径", "保存路径", '增强倍数', 'Fliplr',"Multiply",
         "GaussianBlur", "ranslate_X_px", "ranslate_Y_px","Affine_scale", "Affine_rotate"]
        self.Table_ImgEnhance = Mainwindow_Label_table(10,2,name_list,self)  #表格
        EnhanceList = self.Table_ImgEnhance.widget2()  #控件
        return EnhanceList


    def FormatTrans(self):
        name_list = ["图像&标签原路径", "保存新格式路径", '选择格式', '类别']
        self.Table_Format = Mainwindow_Label_table(4,2,name_list,self)
        Formatwidget = self.Table_Format.widget3()
        return Formatwidget

    def tabChanged(self):
        if self.leftwidget.currentIndex() == 2:
            if self.labelImgsPath != '':
                self.Table_ImgEnhance.Tabchanged_path()

    def newProject(self):  #新建工程
        self.Type_ = "NewProject"
        self.proj_dir = self.mainWindow_.DirPath  # 工程目录
        self.Weights_path = MK_init_dir(self.proj_dir, 'Weights')

        if ODModule_config.read_value('TrainAndTest', 'page') == "1":
            self.trainWidget.clearShow()
            self.testWidget.clearShow()
            self.trainWidget.Weights_path = self.Weights_path
            self.trainWidget.projectTask = self.testWidget.projectTask = self.projectTask
            self.clear_modelComBox()
            self.testWidget.proj_dir = self.proj_dir

        self.labelList.CLASS_()
        self.OpenDisplay()
        self.ToolTip()
        self.saveSettings()#

    def clear_modelComBox(self):
        self.trainWidget.AddModelSelect()
        self.testWidget.AddModelSelect()
        self.Tablabel.imgspathLineEdit.clear()
        self.Tablabel.HalfAuto.clear()
        self.Tablabel.CurrentLabel.clear()

    def OpenDisplay(self):
        if ODModule_config.read_value('OpenDisplay', 'page') == "Label":
            self.actionTool.displayLabelPage()
        if ODModule_config.read_value('OpenDisplay', 'page') == "FTP":
            self.actionTool.displayLabelPage()
            self.displayFtpPage()

    def closeAllRunning(self):
        if ODModule_config.read_value('Industry', 'page') == "1":
            self.IndustryWidget.exitIndustryModel()
            self.IndustryWidget.clearModelAndThread()
        if ODModule_config.read_value('TrainAndTest', 'page') == "1":
            self.trainWidget.label.clsoeCpuAndGpu()
            self.testWidget.label.clsoeCpuAndGpu()
        self.mainWindow_slider.close()  #

    def ToolTip(self):
        self.setToolTip("%s" % self.xmlFilePath)
        self.setStatusTip(self.toolTip())

    def quit(self):
        # from PyQt5 import QtWidgets
        # QtWidgets.qApp.quit()
        # app = QApplication.instance()
        # app.quit()
        self.closeAllRunning()
        self.saveSettings()
        try:
            os._exit(5)
        except Exception as e:
            print(str(e))

    def closeEvent(self, event):
        try:
            reply =QMessageBox(QMessageBox.Question, self.tr("提示"),self.tr("确定要退出吗？"), QMessageBox.NoButton, self)
            yr_btn = reply.addButton(self.tr("退出"), QMessageBox.YesRole)
            reply.addButton(self.tr("最小化到托盘"),QMessageBox.NoRole)
            reply.exec_()
            if reply.clickedButton() == yr_btn:
                if ODModule_config.read_value('OpenCode', 'page') == "0":
                    self.closeAllRunning()
                    self.saveSettings()
                    event.accept()
                    print('main thread is {}'.format(threading.current_thread().name))
                    try:
                        os._exit(5)
                    except Exception as e:
                        print(str(e))
                else:
                    self.codeWidget_.show()
                    self.codeWidget_.clearLine()
                    event.ignore()
            else:
                if self.tray.isVisible():
                    self.hide()
                    event.ignore()
        except Exception as e:
            print(str(e))

    def openMyProject2(self):
        self.saveSettings()
        self.openMyProject('openPro')

    def openMyProject(self, isOpenPro):
        self.Type_ = 'RecentProject'
        if isOpenPro == 'openPro':
            path = os.path.dirname('') if '' else '.'
            filters = 'proj files (*.proj)'
            xmlFilePath = (
                QFileDialog.getOpenFileName(self, '%s - Choose project file' % __appname__, path, filters))
            if xmlFilePath[0] == '':
                return
            self.xmlFilePath = xmlFilePath[0]

        if not os.path.exists(self.xmlFilePath):
            news_delete_project = '此工程文件不存在,是否要删除？'
            customMsgBox, cancelButton, OKButton = news_box(news_delete_project)
            button = customMsgBox.clickedButton()
            if button == cancelButton:
                return
            if button == OKButton:
                self.mainWindow_.deleteTxtWidgetItem()
                recentpro = dir_root() + os.sep + 'Config/recentProject.txt'
                f = open(recentpro)
                aa = f.readlines()
                with open(recentpro, 'w') as w:
                    for l in aa:
                        if self.xmlFilePath not in l:
                            w.write(l)
                return
        self.mainWindow_.close()
        self.showMaximized()
        self.show()
        self.ToolTip()
        # -----------开始获取工程问文件下的参数----------------
        parseXml = ParseXml(self.xmlFilePath)
        self.para_Cfg = parseXml.parseXml() #读取工程文件参数
        self.getLabelValue(self.para_Cfg) #获取Label下的参数
        self.proj_dir = os.path.dirname(self.xmlFilePath)
        if ODModule_config.read_value('TrainAndTest', 'page') == "1":
            self.trainWidget.clearShow()
            self.testWidget.clearShow()
            self.trainWidget.getTrainValue(self.para_Cfg) #获取Train下的参数
            self.trainWidget.refreshTrainInterface(len(self.mImgList))
            self.trainWidget.projectTask = self.testWidget.projectTask = self.projectTask
            self.clear_modelComBox()
            self.testWidget.getTestValue(self.para_Cfg) #获取Test下的参数
        self.LoadAnnotations()
        self.importDirImages(self.labelImgsPath)

        if self.labelClasses == '':
            self.labelClasses = []
        self.refreshLabelInterface()
        self.labelList.CLASS_()
        self.OpenDisplay()
        if len(self.mImgList) > 0:
            self.setFitWindow()

    def refreshLabelInterface(self):
        self.Tablabel.imgspathLineEdit.setText(self.labelImgsPath)

    def exportProjectAs(self):
        print('导出')
        # self.saveSettings()
        # parseXml = ParseXml(self.xmlFilePath)
        # ProjectMessagesDict, labelDict, trainsettingsDict, trainresultDict, testSettingsDict, testResultsDict = parseXml.parseXml()
        # pth.ProjectToHtml(projectName, labelImgsPath, labelClasses, InputImagesSize, Epochs,
        #                   BatchSize, ValidateSplit,
        #                   LearningRate, IgnoreThresh, TrainTime, TrainTotalLoss, TrainValLoss, TrainEndEpochs,
        #                   TrainDate, TestImagesPath,
        #                   self.OK_Path, self.NG_Path, Score, IOU, TotalTestImages, NGImagesNum, NGImagesRate,
        #                   TotalTestTime, AverageTestTimePerImage, TestDate)

    def getLabelValue(self,para_Cfg):
        self.projectPath = para_Cfg['projectPath']
        self.projectTask = para_Cfg['projectTask']
        self.labelImgsPath = para_Cfg['labelImagesPath']

    def contactus(self):  #
        news_contactus = self.tr("章 鱼 博 士 AI 算 法 平 台") + (
                    '\n' + '\n' + '制作:武振昕、马聪' + '\n' + '美术:罗楠沁' + '\n' + '监制:周晓毅、李翌辉、李宝红')
        customMsgBox, cancelButton = news_box2(news_contactus)
        button = customMsgBox.clickedButton()
        if button == cancelButton:
            return

    def saveSettings(self):
        self.saveSettings_thread = threading.Thread(target=self.saveSettings_, args='')
        self.saveSettings_thread.daemon = True
        self.saveSettings_thread.start()
        self.saveSettings_thread.join()

    def saveSettings_(self):
        LabelClass_ = []
        for  i in self.nameDict.keys(): #获取现在有的类别
            if len(self.nameDict[i])!=0 and i != 'All':
                LabelClass_.append(i)

        self.settings.data = {
            SETTING_AUTO_SAVE: self.autoSaving.isChecked(),
            SETTING_SINGLE_CLASS: self.singleClassMode.isChecked(),
            SETTING_RECENT_FILES: self.recentFiles,
            SETTING_SAVE_DIR: self.labelImgsPath,
            SETTING_WIN_SIZE: (self.size().width(), self.size().height()),
            SETTING_WIN_POSE: (self.pos().x(), self.pos().y()),
            SETTING_LINE_COLOR: self.lineColor.rgba(),
            SETTING_FILL_COLOR: self.fillColor.rgba(),
        }
        try:
            self.settings.data[SETTING_WIN_STATE] = list(self.saveState().data())
        except Exception as e:
            print(str(e))
            pass
        self.settings.save()

        self.isProjectAddtoRecent = False
        if self.projectPath != self.xmlFilePath:
            self.isProjectAddtoRecent = True
            self.projectPath = self.xmlFilePath

        trainSaveWeigth = os.path.join(os.path.dirname(self.projectPath), 'Weights')
        testIOU = '0.55'

        if ODModule_config.read_value('TrainAndTest', 'page') == "1":  #打开训练和推理界面
            # self.trainWidget.label.label1.setText('%s Images' % len(self.mImgList))
            Value_ = GetTrainAndTest_value(self.trainWidget,self.testWidget)
            od_cfg = Value_.GetValue()

        # 选择新建工程+关闭训练和推理界面
        elif self.Type_ == 'NewProject' and ODModule_config.read_value('TrainAndTest', 'page') != "1":
            od_cfg = GetValue_None()

        # 选择最近工程+关闭训练和推理界面
        elif self.Type_ == 'RecentProject' and ODModule_config.read_value('TrainAndTest', 'page') != "1":
            od_cfg = self.para_Cfg

        od_cfg["trainSaveWeigth"] = trainSaveWeigth
        od_cfg["testIOU"] = testIOU
        od_cfg["projectPath"] = self.projectPath
        od_cfg["projectTask"] = self.projectTask
        od_cfg["labelImagesPath"] = self.labelImgsPath
        od_cfg["labelClasses"] = LabelClass_
        SaveProjectToXml(od_cfg,self.isProjectAddtoRecent)  #

        try:
            self.trainWidget.od_cfg = self.testWidget.od_cfg = od_cfg
            self.trainWidget.labelImgsPath = self.testWidget.labelImgsPath = self.labelImgsPath
            self.trainWidget.labelClasses = self.testWidget.labelClasses = LabelClass_
            if self.proj_dir:
                self.testWidget.resultParaLineEdit.setText(os.path.join(self.proj_dir,'Result'))
        except Exception as e:
            print(str(e))
            pass
        print('child thread is '.format(threading.current_thread().name))

    def getSavePath(self, file, mark = False):
        self.labelClasses.clear()
        if mark:
            self.labelImgsPath = str(QFileDialog.getExistingDirectory(self, '%s-Open Directory'% __appname__, None, QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks))
        else:
            self.labelImgsPath = file.text()
        if self.labelImgsPath == '':
            return
        self.labelImgsPath = self.labelImgsPath.replace('/',os.sep)
        file.setText(self.labelImgsPath)
        self.canvas.lab1hide()
        self.actions.No_defect.setEnabled(True)
        self.LoadAnnotations()
        self.importDirImages(self.labelImgsPath)
        if ODModule_config.read_value('TrainAndTest', 'page') == "1":  #打开训练和推理界面
            self.trainWidget.IMPATH = self.labelImgsPath

    def LoadAnnotations(self):
        if self.projectTask != '图像分类':
            self.XmlLabel = False
            self.TextBrowser.append('开始加载标签文件>>>\n请等待标签加载')
            self.LoadXmlThread = threading.Thread(target=self.LoadLabel, args='')
            self.LoadXmlThread.daemon = True
            self.LoadXmlThread.start()

    def LoadLabel(self):
        try:
            # AnnotationList = scanAllImages(self.labelImgsPath, extensions_=['xml', 'json', 'txt'])
            AnnotationList = scanAllImages(self.labelImgsPath)

            for ann in AnnotationList:

                filepath1 = os.path.join(self.labelImgsPath, ann)
                filepath_xml = os.path.splitext(filepath1)[0]+'.xml'
                filepath_json = os.path.splitext(filepath1)[0]+'.json'
                filepath_txt = os.path.splitext(filepath1)[0]+'.txt'

                if os.path.exists(filepath_xml) :
                    from xml.dom.minidom import parse
                    tree = parse(filepath_xml)
                    for node in tree.getElementsByTagName('name'):
                        section = node.childNodes[0]
                        if filepath1 not in self.nameDict[str(section.data)]:
                            self.nameDict[str(section.data)].append(filepath1)

                elif os.path.exists(filepath_json):
                    text = json.load(open(filepath_json))
                    for shape in text.get('shapes', []):
                        if filepath1 not in self.nameDict[shape['label']]:
                            self.nameDict[shape['label']].append(filepath1)

                elif os.path.exists(filepath_txt) and \
                    not os.path.exists(filepath_xml) and \
                    not os.path.exists(filepath_json):
                    text = open(filepath_txt).read()
                    for name in re.findall('(\n|^)(\d+)', text):
                        if filepath1 not in self.nameDict[name[1].rjust(9, '0')]:
                            self.nameDict[name[1].rjust(9, '0')].append(filepath1)

            self.Tablabel.CurrentLabel.clear()
            TextBrowserNews(self.TextBrowser, news='标签加载完成！')
            self.Tablabel.CurrentLabel.addItems(self.nameDict.keys())
        except:
            TextBrowserNews(self.TextBrowser, news='标签错误！')

    def NoDefect(self):  # saveFileAs
        news_delete_project = '确定要转为OK图像吗？(标签会去除)'
        customMsgBox, cancelButton, OKButton = news_box(news_delete_project)
        button = customMsgBox.clickedButton()
        if button == cancelButton:
            return
        if button == OKButton:
            self.canvas.lab1show()
            self.save_status = 1
            self.actions.No_defect.setEnabled(False)
            self.saveFile()

    def xrayClass_func(self,id):
        self.X_ray_page.Xray_Class(self.labelImgsPath, self.filePath, self.xmlFilePath, id)

    def SetTruePage(self,page,Dock,label=True):
        self.close_allToolbar()
        if label:
            self.exitLabel()
        if Dock:
            Dock.show()
        for i in self.daohangActions:
            i.setEnabled(True)
        page.setEnabled(False)
        self.stack.setCurrentIndex(self.AllDockWdiget.index(Dock))

    def close_allToolbar(self):
        for i in self.AllDockWdiget:
            i.close()

    def IndustryModel(self):
        self.IndustryWidget.proj_path = os.path.dirname(self.xmlFilePath)  # 工程路径传到工程模式下面
        self.IndustryWidget.w1 = self.centralWidget().width() - 2.0
        self.IndustryWidget.h1 = self.centralWidget().height() - 2.0
        self.IndustryDockWidget.show()
        self.toolsdaohang.close()
        self.SetTruePage(self.Industry_model, self.IndustryDockWidget)

    def TrainandTest(self,page,dock):
        self.saveSettings()
        self.SetTruePage(page, dock)

    def displayTrainPage(self):
        self.TrainandTest(self.trainpageAction,self.TrainDockWidget)

    def displayTestPage(self):
        self.TrainandTest(self.testpageAction,self.TestDockWidget)

    def displayFtpPage(self):
        e = 2.0  # So that no scrollbars are generated.
        self.FTPWidget.tree_.w1 = self.FTPWidget.loaclTree.w1 = self.centralWidget().width() - e
        self.FTPWidget.tree_.h1 = self.FTPWidget.loaclTree.h1 = self.centralWidget().height() - e
        self.SetTruePage(self.FTPpageAction,self.FTPDockWidget)

    def displayClassical(self):
        self.SetTruePage(self.ClassicalAction,self.ClassicalDock)

    def display3dPage(self):
        try:
            if self.MainWidget3d == None:
                from Module.module_3D.main_3D import MainWidget_3d
                self.MainWidget3d = MainWidget_3d()
                self.D3dDockWidget = self.Stack_widget(self.MainWidget3d, True)
        except Exception as e:
            print(str(e))

        self.SetTruePage(self.D3DpageAction,self.D3dDockWidget)

    def exitLabel(self):
        if self.labelFlag == True:
            self.toolsLabel.deleteLater()
            if ODModule_config.read_value('x-ray_tools', 'page') == "1":
                self.toolXray.deleteLater()
            self.labelFlag = False

    def label(self):
        self.toolsLabel = self.toolbar('ToolsLabel', None, Qt.RightToolBarArea)
        addActions(self.toolsLabel, self.actions.beginner)
        # ----------------添加Xray工具栏----------------
        if ODModule_config.read_value('x-ray_tools', 'page') == "1":
            self.addToolBarBreak(area=Qt.RightToolBarArea)
            self.toolXray = self.toolbar('Xray', None, Qt.RightToolBarArea)
            addActions(self.toolXray, self.actions.Xray)

    def set_format(self, save_format):
        if save_format == 'PascalVOC':
            self.actions.save_format.setText("PascalVOC")
            self.actions.save_format.setIcon(QIcon(':/icons/format_voc.png'))
            self.usingPascalVocFormat = True
            self.usingYoloFormat = False

    def change_format(self):
        if self.usingYoloFormat:
            self.set_format("PascalVOC")

    #---------------------------------Labelimg-------------------------

    def setDirty(self):
        self.dirty = True
        self.actions.save.setEnabled(True)

    def setClean(self):
        self.dirty = False
        self.actions.save.setEnabled(False)
        if self.projectTask != '图像分类':
            self.actions.create.setEnabled(True)
            self.actions.create_poly.setEnabled(True)

    def toggleActions(self, value=True):
        """Enable/Disable widgets which depend on an opened image."""
        for z in self.actions.zoomActions:
            z.setEnabled(value)

    def status(self, message, delay=5000):
        self.statusBar().showMessage(message, delay)

    def resetState(self):
        self.itemsToShapes.clear()
        self.shapesToItems.clear()
        self.labelList.clear()
        self.filePath = None
        self.imageData = None
        self.labelFile = None
        self.canvas.resetState()
        self.labelCoordinates.clear()

    def currentItem(self):
        items = self.labelList.selectedItems()
        if items:
            return items[0]
        return None

    def addRecentFile(self, filePath):
        if filePath in self.recentFiles:
            self.recentFiles.remove(filePath)
        elif len(self.recentFiles) >= self.maxRecent:
            self.recentFiles.pop()
        self.recentFiles.insert(0, filePath)

    def beginner(self):
        return self._beginner

    def advanced(self):
        return not self.beginner()

    def getAvailableScreencastViewer(self):
        osName = platform.system()
        if osName == 'Windows':
            return ['C:\\Program Files\\Internet Explorer\\iexplore.exe']
        elif osName == 'Linux':
            return ['xdg-open']
        elif osName == 'Darwin':
            return ['open', '-a', 'Safari']

    def showTutorialDialog(self):
        subprocess.Popen(self.screencastViewer + [self.screencast])

    def showInfoDialog(self):
        msg = INFORMATION_CONTENTS.format(__appname__, __version__, sys.version_info)
        QMessageBox.information(self, INFORMATION_DETAIL, msg)  # u'Name:{0} \nApp Version:{1} \n{2} '   u'Information'

    def createShape(self,value_):
        self.canvas.create_value = value_
        assert self.beginner()
        self.canvas.setEditing(False)
        self.actions.create.setEnabled(False)
        self.actions.create_poly.setEnabled(False)

    def toggleDrawingSensitive(self, drawing=True):
        """In the middl e of drawing, toggling between modes should be disabled."""
        if not drawing and self.beginner():
            # Cancel creation.
            print('Cancel creation.')
            self.canvas.setEditing(True)
            self.canvas.restoreCursor()
            if self.projectTask != '图像分类':
                self.actions.create.setEnabled(True)
                self.actions.create_poly.setEnabled(True)


    def initLoginFtp(self):
        self.X_ray_page.Ftp = FTP(
            host='czccd.svolt.cn',
            user='CM02YCXR01',
            passwd='SVOLT@2021',
            logger=self.logger
        )

    def Upload_(self):
        if self.ini_ == 0:
            self.main.put({'stop': True})
            TextBrowserNews(self.TextBrowser, news='停止上传')
            self.Upload_setText()
            self.ini_ = 1
            return
        else:
            self.initLoginFtp()
            self.TextBrowser.clear()
            sub = queue.Queue()
            self.main.queue.clear()
            self.ini_ = 0
            TextBrowserNews(self.TextBrowser, news='正在上传...')
            self.Upload.setText(STOP_UPLOAD)
            self.Upload.setStyleSheet('''QPushButton{background:rgb(255,0,0);
                border-radius:5px;}QPushButton:hover{background:blue;}''')

            self.UPloadThread = threading.Thread(target=self.UPload_FTP, args=(self.main, sub))
            self.UPloadThread.daemon = True
            self.UPloadThread.start()

            self.GetValThread = threading.Thread(target=self.GetVal_Log, args=(self.main, sub))
            self.GetValThread.daemon = True
            self.GetValThread.start()

    def UPload_FTP(self, main=None, sub=None):
        self.X_ray_page.Xray_Class(self.labelImgsPath, self.filePath, self.xmlFilePath, '上传', main, sub)


    def GetVal_Log(self, main=None, sub=None):  #
        while True:
            time.sleep(0.1)
            try:
                flags = main.get(block=False)
            except:
                flags = {}
            if flags.get('stop', False):
                main.put({'stop': True})
                break
            try:
                result = sub.get(block=False)
                if result['idx'] == -1:
                    TextBrowserNews(self.TextBrowser, news='路径下没有文件')
                    self.Upload_setText()
                    self.ini_ = 1
                    main.put({'stop': True})
                    break
                if result['idx'] == result['total']:
                    connect_ = "第%s/%s ——>%s" % (result['idx'], result['total'], result['msg'])
                    TextBrowserNews(self.TextBrowser, news=connect_)
                    TextBrowserNews(self.TextBrowser, news='上传完成')
                    self.Upload_setText()
                    self.ini_ = 1
                    break
                if int(result['idx']) == 0:
                    self.TextBrowser.append(result['path'])
                else:
                    connect_ = "第%s/%s ——>%s" % (result['idx'], result['total'], result['msg'])
                    TextBrowserNews(self.TextBrowser, news=connect_)
            except Exception as e:
                result = {}

    def Upload_setText(self):
        self.Upload.setText(UPLOAD_FTP)
        self.Upload.setStyleSheet('''QPushButton{background:rgb(0,125,0);
            border-radius:5px;}QPushButton:hover{background:blue;}''')

    def shapeSelectionChanged(self, selected=False):
        try:
            if self._noSelectionSlot:
                self._noSelectionSlot = False
            else:
                shape = self.canvas.selectedShape
                if shape:
                    self.shapesToItems[shape].setSelected(True)
                else:
                    self.labelList.clearSelection()
            self.actions.delete.setEnabled(selected)
            self.actions.copy.setEnabled(selected)
            self.actions.edit.setEnabled(selected)
        except:
            pass

    def addLabel(self, shape):
        if shape is None:
            return
        item = HashableQListWidgetItem(shape.label)
        item.setFlags(item.flags() | Qt.ItemIsUserCheckable)
        item.setCheckState(Qt.Checked)
        item.setBackground(generateColorByText(shape.label))
        self.itemsToShapes[item] = shape
        self.shapesToItems[shape] = item
        self.labelList.addItem(item)

    def remLabel(self, shape):
        if shape is None:
            return
        item = self.shapesToItems[shape]
        self.labelList.takeItem(self.labelList.row(item))
        del self.shapesToItems[shape]
        del self.itemsToShapes[item]

    def loadLabels(self, shapes):  #
        s = []
        if shapes == []:
            self.canvas.lab1show()
            self.actions.No_defect.setEnabled(False)
        else:
            self.canvas.lab1hide()
            self.actions.No_defect.setEnabled(True)

        for label, points, line_color, fill_color, difficult,score in shapes:
            shape = Shape(label=label,score=score)
            for x, y in points:
                shape.addPoint(QPointF(x, y))
            shape.difficult = difficult
            shape.close()
            s.append(shape)
            if line_color:
                shape.line_color = QColor(*line_color)  #
            else:
                shape.line_color = generateColorByText(label)

            if fill_color:
                shape.fill_color = QColor(*fill_color)
            else:
                shape.fill_color = generateColorByText(label)

            self.addLabel(shape)  #
        self.canvas.loadShapes(s)

    def saveLabels(self, annotationFilePath):  ####
        def format_shape(s):
            return dict(label=s.label,
                        line_color=s.line_color.getRgb(),
                        fill_color=s.fill_color.getRgb(),
                        points=[(p.x(), p.y()) for p in s.points],
                        difficult=s.difficult)

        if self.save_status == 0:  # 0表示正常保存有类别的Xml文件，1表示保存没有类别的Xml文件
            shapes = [format_shape(shape) for shape in self.canvas.shapes]
        else:
            shapes = []

        if self.labelFile is None:
            self.labelFile = LabelFile()
            self.labelFile.verified = self.canvas.verified
        try:
            if self.usingPascalVocFormat is True:
                annotationFilePath += XML_EXT
                print('Img: ' + self.filePath + ' -> Its xml: ' + annotationFilePath)

                saveFile_thread = threading.Thread(target=self.saveFileThread, args=(annotationFilePath, shapes,
                             self.filePath, self.imageData,self.lineColor.getRgb(), self.fillColor.getRgb()))
                saveFile_thread.daemon = True
                saveFile_thread.start()

                list_ = [label['label'] for label in shapes]  #获取当前图像的类别列表
                list_ = list(set(list_))
                #把self.nameDict字典的类别和list做对比，把self.nameDict多出来的保存下来，判断里面有没有当前图像，有的话就删除掉
                namedict = [i for i in self.nameDict.keys() if i not in list_ and i!="All" ]

                for name in namedict:
                    if self.filePath in self.nameDict[name] and name != "All":
                        self.nameDict[name].remove(self.filePath)
                        self.fileListWidget.setCurrentRow(self.fileListWidget.currentRow())

                        self.IDX_ALL = int(len(self.compressPicPath_))
                        self.IDX_CURRENT = self.fileListWidget.currentRow()

                        self.mask = True
                        if self.IDX_CURRENT == self.IDX_ALL:
                            self.SetIDX = self.IDX_ALL-1
                        elif self.IDX_CURRENT + 1 == self.IDX_ALL:
                            self.SetIDX = self.IDX_ALL-1
                        else:
                            self.SetIDX = self.IDX_CURRENT-1
                        if name  == self.Tablabel.CurrentLabel.currentText():
                            self.fileListWidget.takeItem(self.fileListWidget.currentRow())

                #判断list的类别有没有新的，有的话就添加到CurrentLabel里面
                [self.Tablabel.CurrentLabel.addItem(i) for i in list_ if i not in self.nameDict.keys() ]

                # 遍历一下self.nameDict字典里是否有对应的图像，如果没有则添加d
                [self.nameDict[label].append(self.filePath) for label in list_ if self.filePath not in self.nameDict[label]]

                if len(self.nameDict[self.Tablabel.CurrentLabel.currentText()]) == 0:
                    self.setClean()
                    self.Tablabel.CurrentLabel.setCurrentIndex(0)

                #判断nameDict里的类别字典,如果为空则删除掉对应的currentlabel
                for i in list(self.nameDict.keys()):
                    if len(self.nameDict[i]) == 0:
                        self.Tablabel.CurrentLabel.removeItem(self.Tablabel.CurrentLabel.findText(i))
                        del self.nameDict[i]


            else:
                self.labelFile.save(annotationFilePath, shapes, self.filePath, self.imageData,
                                    self.lineColor.getRgb(), self.fillColor.getRgb())
            return True
        except LabelFileError as e:
            self.errorMessage(u'Error saving label data', u'<b>%s</b>' % e)
            return False

    def saveFileThread(self, annotationFilePath, shapes, filePath, imageData, getRgb, Color_getRgb):
        if self.labelFile is None:
            self.labelFile = LabelFile()
            self.labelFile.verified = self.canvas.verified
        self.labelFile.savePascalVocFormat(annotationFilePath, shapes, filePath, imageData, getRgb, Color_getRgb)

    def copySelectedShape(self):
        self.addLabel(self.canvas.copySelectedShape())
        self.shapeSelectionChanged(True)

    def newShape(self):
        """Pop-up and give focus to the label editor.
        position MUST be in global coordinates.
        """
        if len(self.labelClasses) > 0:
            self.labelDialog = LabelDialog(
                parent=self, listItem=self.labelClasses)

        if self.singleClassMode.isChecked() and self.lastLabel:
            text = self.lastLabel
        else:
            text = self.labelDialog.popUp(text=self.prevLabelText)
            self.lastLabel = text
        # Add Chris
        if text is not None:
            self.prevLabelText = text
            generate_color = self.lineColor  # 改颜色
            shape = self.canvas.setLastLabel(text, generate_color, generate_color)
            self.addLabel(shape)
            if self.beginner():  # Switch to edit mode.
                self.canvas.setEditing(True)
                if self.projectTask != '图像分类':
                    self.actions.create.setEnabled(True)
                    self.actions.create_poly.setEnabled(True)
            self.setDirty()

            if text not in self.labelClasses:
                self.labelClasses.append(text)
            # for i in range(self.labelList.count()):
            #     # self.labelClasses
            #     if self.labelList.item(i).text() not in self.labelClasses:
            #         self.labelClasses.append(self.labelList.item(i).text())
        else:
            self.canvas.resetAllLines()

    def scrollRequest(self, delta, orientation):
        units = - delta / (8 * 15)
        bar = self.scrollBars[orientation]
        bar.setValue(bar.value() + bar.singleStep() * units)

    def setZoom(self, value):
        self.actions.fitWindow.setChecked(False)
        self.zoomMode = self.MANUAL_ZOOM
        self.zoomWidget.setValue(value)

    def addZoom(self, increment=10):
        self.setZoom(self.zoomWidget.value() + increment)

    def zoomRequest(self, delta):
        h_bar = self.scrollBars[Qt.Horizontal]
        v_bar = self.scrollBars[Qt.Vertical]
        h_bar_max = h_bar.maximum()
        v_bar_max = v_bar.maximum()
        cursor = QCursor()
        pos = cursor.pos()
        relative_pos = QWidget.mapFromGlobal(self, pos)
        cursor_x = relative_pos.x()
        cursor_y = relative_pos.y()
        w = self.scrollArea.width()
        h = self.scrollArea.height()
        margin = 0.1
        move_x = (cursor_x - margin * w) / (w - 2 * margin * w)
        move_y = (cursor_y - margin * h) / (h - 2 * margin * h)

        # clamp the values from 0 to 1
        move_x = min(max(move_x, 0), 1)
        move_y = min(max(move_y, 0), 1)

        # zoom in
        units = delta / (8 * 15)
        scale = 10
        self.addZoom(scale * units)

        # get the difference in scrollbar values
        # this is how far we can move
        d_h_bar_max = h_bar.maximum() - h_bar_max
        d_v_bar_max = v_bar.maximum() - v_bar_max
        new_h_bar_value = h_bar.value() + move_x * d_h_bar_max
        new_v_bar_value = v_bar.value() + move_y * d_v_bar_max
        h_bar.setValue(new_h_bar_value)
        v_bar.setValue(new_v_bar_value)

    def setFitWindow(self, value=True):
        self.zoomMode = self.FIT_WINDOW if value else self.MANUAL_ZOOM
        self.adjustScale()

    def loadFile(self, filePath=None):  
        """Load the specified file, or the last opened file if None."""
        # -----计算是第几张-----
        self.labelList.clear()
        if self.compressPicPath_ != []:
            idx_total = self.compressPicPath_.index(str(filePath))
            self.fileListWidget.setCurrentItem(self.fileListWidget.item(idx_total))
        if self.projectTask == '目标检测':
            self.resetState()
        self.canvas.setEnabled(False)
        if filePath is None:
            filePath = self.settings.get(SETTING_FILENAME)
        unicodeFilePath = ustr(str(filePath))
        if unicodeFilePath and os.path.exists(unicodeFilePath):
            self.X_ray_page.PanDuan(unicodeFilePath, self.xmlFilePath)

            if LabelFile.isLabelFile(unicodeFilePath):
                try:
                    self.labelFile = LabelFile(unicodeFilePath)
                except LabelFileError as e:
                    self.errorMessage(u'Error opening file',
                                      (u"<p><b>%s</b></p>"
                                       u"<p>Make sure <i>%s</i> is a valid label file.")
                                      % (e, unicodeFilePath))
                    self.status("Error reading %s" % unicodeFilePath)
                    return False
                self.imageData = self.labelFile.imageData
                self.lineColor = QColor(*self.labelFile.lineColor)
                self.fillColor = QColor(*self.labelFile.fillColor)
            else:
                self.imageData = read(unicodeFilePath, None)
                self.labelFile = None

            image = QImage.fromData(self.imageData)
            if image.isNull():
                self.errorMessage(u'Error opening file',
                                  u"<p>Make sure <i>%s</i> is a valid image file." % unicodeFilePath)
                self.status("Error reading %s" % unicodeFilePath)
                return False
            self.status("Loaded %s" % os.path.basename(unicodeFilePath))
            self.image = image
            self.filePath = unicodeFilePath
            rotation = get_rotation(unicodeFilePath)
            pixmap = QPixmap.fromImage(image)
            pixmap = pixmap.transformed(QTransform().rotate(rotation))
            self.canvas.loadPixmap(pixmap)
            if self.labelFile:
                self.loadLabels(self.labelFile.shapes)
            self.setClean()
            self.canvas.setEnabled(True)
            self.adjustScale(initial=True)
            self.paintCanvas()
            self.addRecentFile(self.filePath)
            self.toggleActions(True)

            if self.labelImgsPath is not None:
                xmlPath = os.path.splitext(filePath)[0] + XML_EXT
                if os.path.isfile(xmlPath):
                    self.loadPascalXMLByFilename(xmlPath)

            self.setWindowTitle(__appname__ + ' ' + filePath)

            # Default : select last item if there is at least one item
            # if self.labelList.count():     #默认选择最后标的标签
            #     self.labelList.setCurrentItem(self.labelList.item(self.labelList.count()-1))
            #     self.labelList.item(self.labelList.count()-1).setSelected(True)
            
            self.canvas.setFocus(True)
        else:
            customMsgBox, cancelButton = news_box2('该文件不存在')
            button = customMsgBox.clickedButton()
            if button == cancelButton:
                print(self.labelImgsPath)
                self.importDirImages(self.labelImgsPath)
            return False
        return True

    # def resizeEvent(self, event):
    #     if self.canvas and not self.image.isNull() \
    #             and self.zoomMode != self.MANUAL_ZOOM:
    #         self.adjustScale()
    #     super(MainWindow, self).resizeEvent(event)

    def paintCanvas(self):
        assert not self.image.isNull(), "cannot paint null image"
        self.canvas.scale = 0.01 * self.zoomWidget.value()
        self.canvas.adjustSize()
        self.canvas.update()

    def adjustScale(self, initial=False):
        value = self.scalers[self.FIT_WINDOW if initial else self.zoomMode]()  #
        self.zoomWidget.setValue(int(100 * value))

    def scaleFitWindow(self):
        """Figure out the size of the pixmap in order to fit the main widget."""
        e = 2.0  # So that no scrollbars are generated.
        w1 = self.centralWidget().width() - e
        h1 = self.centralWidget().height() - e
        a1 = w1 / h1
        # Calculate a new scale value based on the pixmap's aspect ratio.
        if self.canvas.pixmap == None:
            w2 = 1600
            h2 = 1600
            a2 = 1
        else:
            w2 = self.canvas.pixmap.width() - 0.0
            h2 = self.canvas.pixmap.height() - 0.0
            a2 = w2 / h2
        return w1 / w2 if a2 >= a1 else h1 / h2

    def scaleFitWidth(self):
        # The epsilon does not seem to work too well here.
        w = self.centralWidget().width() - 2.0
        return w / self.canvas.pixmap.width()

    def loadRecent(self, filename):
        if self.mayContinue():
            self.loadFile(filename)

    def changeSavedirDialog(self, _value=False):
        if self.labelImgsPath is not None:
            path = ustr(self.labelImgsPath)
        else:
            path = '.'
        dirpath = ustr(QFileDialog.getExistingDirectory(self, SHOW_STATE_BAR_MESSAGE_2 % __appname__, path,
                                                        QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks))
        if dirpath is not None and len(dirpath) > 1:
            self.labelImgsPath = dirpath
        self.statusBar().showMessage(SHOW_STATE_BAR_MESSAGE_3 % ('Change saved folder', self.labelImgsPath))
        self.statusBar().show()

    def clearWindow(self):  #
        self.resetState()
        self.TextBrowser.clear()
        self.fileListWidget.clear()
        self.labelList.clear()
        self.mImgList.clear()
        self.compressPicPath_.clear()
        self.mainWindow_slider.close()

    def importDirImages(self, dirpath, imtype=None):
        if dirpath == "":
            return
        if not self.mayContinue() or not dirpath:
            return

        self.filePath = None
        self.fileListWidget.clear()
        self.All_img_list = scanAllImages(self.labelImgsPath)
        self.nameDict.clear()
        self.nameDict['All'] = self.All_img_list


    def Class_change(self, dirpath, imtype=None):
        if dirpath == "":
            return
        if not self.mayContinue() or not dirpath:
            return
        self.fileListWidget.clear()
        if imtype != None:
            self.mImgList = imtype
        else:
            self.mImgList = self.All_img_list

        self.compressPicPath_ = self.mImgList
        # self.openNextImg()
        for imgPath in self.mImgList:
            self.Tablabel.fileListWidget_show(imgPath)
        # self.fileListWidget.setCurrentItem(self.fileListWidget.item(0))


    def openPrevImg(self, _value=False):
        if self.autoSaving.isChecked():
            if self.labelImgsPath is not None:
                if self.dirty is True:
                    self.saveFile_()
            else:
                self.changeSavedirDialog()
                return
        if len(self.compressPicPath_) <= 0:
            return
        if self.filePath is None:
            return
        if self.filePath not in self.compressPicPath_:
            currIndex = 1
        else:
            currIndex = self.compressPicPath_.index(self.filePath)
        if currIndex - 1 >= 0: #判断不让左翻溢出报错
            self.canvas.lab1hide()
            self.actions.No_defect.setEnabled(True)
            filename = self.compressPicPath_[currIndex - 1]
            if filename:
                self.loadFile(filename)

    def openNextImg(self, _value=False):
        if self.autoSaving.isChecked():
            if self.labelImgsPath is not None:
                if self.dirty is True:
                    self.saveFile_()
            else:
                self.changeSavedirDialog()
                return
        if len(self.compressPicPath_) <= 0:
            return
        filename = None
        if self.filePath is None:
            filename = self.compressPicPath_[0]
        else:
            if self.filePath not in self.compressPicPath_ and self.mask == False:
                currIndex = -1
            else:
                if self.mask == True:
                    currIndex = self.SetIDX+1
                    self.mask = False
                else:
                    currIndex = self.compressPicPath_.index(self.filePath)

            if currIndex + 1 < len(self.compressPicPath_):
                self.canvas.lab1hide()
                self.actions.No_defect.setEnabled(True)
                filename = self.compressPicPath_[currIndex + 1]
        if filename:
            self.loadFile(filename)

    def saveFile_(self, _value=False):  ##
        self.save_status = 0
        self.saveFile()
        self.actions.No_defect.setEnabled(True)

    def saveFile(self, _value=False):  #
        if self.labelImgsPath is not None and len(ustr(self.labelImgsPath)):
            if self.filePath:
                savedFileName = os.path.splitext(self.filePath)[0]
                if savedFileName and self.saveLabels(savedFileName):
                    self.setClean()  #
                    self.statusBar().showMessage('Saved to  %s' % savedFileName)  # 'Saved to  %s'
                    self.statusBar().show()

    def mayContinue(self):
        return not self.dirty

    def errorMessage(self, title, message):
        return QMessageBox.critical(self, title,
                                    '<p><b>%s</b></p>%s' % (title, message))

    def chooseColor1(self):
        color = self.colorDialog.getColor(self.lineColor, COLOR_DIALOG_1,
                                          default=DEFAULT_LINE_COLOR)  # u'Choose line color'
        if color:
            self.lineColor = color  #
            self.canvas.setDrawingColor(color)
            Shape.color_ = color
            self.canvas.update()
            self.setDirty()

    def deleteSelectedShape(self):
        self.remLabel(self.canvas.deleteSelected())
        self.setDirty()
        self.save_status = 1

    def copyShape(self):
        self.canvas.endMove(copy=True)
        self.addLabel(self.canvas.selectedShape)
        self.setDirty()

    def moveShape(self):
        self.canvas.endMove(copy=False)
        self.setDirty()

    def loadPascalXMLByFilename(self, xmlPath):
        if self.filePath is None:
            return
        if os.path.isfile(xmlPath) is False:
            return
        self.set_format("PascalVOC")
        tVocParseReader = PascalVocReader(xmlPath)
        shapes = tVocParseReader.getShapes()
        self.loadLabels(shapes)
        self.canvas.verified = tVocParseReader.verified

    def CanvasPart(self):   #画布部分
        self.zoomWidget = ZoomWidget()
        self.colorDialog = ColorDialog(parent=self)
        self.canvas = Canvas(parent=self)  #
        self.canvas.zoomRequest.connect(self.zoomRequest)
        self.canvas.openNextImg.connect(self.openNextImg)
        self.canvas.openPrevImg.connect(self.openPrevImg)
        self.scrollArea = QScrollArea()
        self.scrollArea.setWidget(self.canvas)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.scrollBars = {
            Qt.Vertical: self.scrollArea.verticalScrollBar(),
            Qt.Horizontal: self.scrollArea.horizontalScrollBar()
        }
        self.canvas.setFont(APPFONT)
        self.canvas.scrollRequest.connect(self.scrollRequest)
        self.canvas.newShape.connect(self.newShape)
        self.canvas.shapeMoved.connect(self.setDirty)
        self.canvas.selectionChanged.connect(self.shapeSelectionChanged)
        self.canvas.drawingPolygon.connect(self.toggleDrawingSensitive)
        self.canvas.nextImg.connect(self.videoWidget.Start_Video)
        self.canvas.nextImg_left.connect(self.videoWidget.Start_Video_Left)

        self.canvas.start_video_img.connect(self.videoWidget.Start_Video) #空格控制播放

        self.setCentralWidget(self.scrollArea)

    def InitLabelimg(self):
        self.recentFiles = []
        self.maxRecent = 7
        self.lineColor = None
        self.fillColor = None
        if self.settings.get(SETTING_RECENT_FILES):
            if have_qstring():
                recentFileQStringList = self.settings.get(SETTING_RECENT_FILES)
                self.recentFiles = [ustr(i) for i in recentFileQStringList]
            else:
                self.recentFiles = self.settings.get(SETTING_RECENT_FILES)

        zoom = QWidgetAction(self)
        zoom.setDefaultWidget(self.zoomWidget)
        self.zoomMode = self.MANUAL_ZOOM
        self.scalers = {
            self.FIT_WINDOW: self.scaleFitWindow,
            self.FIT_WIDTH: self.scaleFitWidth,
            # Set to one to scale to 100% when loading files.
            self.MANUAL_ZOOM: lambda: 1,
        }

        self.autoSaving = QAction(AUTO_SAVING, self)
        self.autoSaving.setCheckable(True)
        # self.autoSaving.setChecked(settings.get(SETTING_AUTO_SAVE, False)) #自动保存
        self.autoSaving.setChecked(True)

        self.singleClassMode = QAction(SINGLE_CLASS_MODE, self)
        self.singleClassMode.setShortcut("Ctrl+Shift+S")
        self.singleClassMode.setCheckable(True)
        self.singleClassMode.setChecked(True)

        self.lastLabel = None

        self.statusBar().showMessage(SHOW_MESSAGE_1 % __appname__)
        self.statusBar().show()
        self.image = QImage()
        width, height = self.settings.get(SETTING_WIN_SIZE, (800, 600))
        size = QSize(width, height)

        x, y = self.settings.get(SETTING_WIN_POSE, (0, 0))
        position = QPoint(x, y)
        self.resize(size)
        self.move(position)

        self.restoreState(bytes(self.settings.get(SETTING_WIN_STATE, QByteArray())))
        data = self.settings.get(SETTING_WIN_STATE, [])
        self.restoreState(QByteArray(bytes(data)))
        rgba = self.settings.get(SETTING_LINE_COLOR, 2147548928)
        Shape.line_color = self.lineColor = QColor(rgba)
        rgba = self.settings.get(SETTING_FILL_COLOR, 2164195328)
        Shape.fill_color = self.fillColor = QColor(rgba)
        Shape.color_ = self.lineColor
        self.canvas.setDrawingColor(self.lineColor)
        # Add chris
        Shape.difficult = False
        # Callbacks:
        self.zoomWidget.valueChanged.connect(self.paintCanvas)  #
        # Display cursor coordinates at the right of status bar
        self.labelCoordinates = QLabel('')
        self.statusBar().addPermanentWidget(self.labelCoordinates)

def get_main_app(argv=[]):
    """
    Standard boilerplate Qt application code.
    Do everything but app.exec_() -- so that we can test the application in one thread
    """
    win = MainWindow()
    return win

def single_program():
    from PyQt5.QtNetwork import QLocalSocket, QLocalServer
    try:
        logger = init_log()
        app = QApplication(sys.argv)
        serverName = 'OD-Vision'
        socket = QLocalSocket()
        socket.connectToServer(serverName)
        # 判定应用服务是否正常链接，如正常则证明程序实例已经在运行
        if socket.waitForConnected(500):
            app.quit()
        # 如果没有实例运行，则创建应用服务器并监听服务
        else:
            localServer = QLocalServer()
            localServer.listen(serverName)
            app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
            app.setWindowIcon(QIcon(":/icons/1-2"))
            qApp.processEvents()  # 处理主进程事件
            app.setApplicationName(__appname__)
            # w = MainWindow()
            # w.show()
            window = get_main_app(sys.argv)
            sys.exit(app.exec_())
    except Exception as e:
        print(str(e))
        logger.log(Logger.ERROR, str(e), exception=True)

def normal_program():
    try:
        logger = init_log()
        app = QApplication(sys.argv)
        app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
        app.setWindowIcon(QIcon(":/icons/1-2"))
        # sp = MySplash()
        # sp.show()
        # load_dataSplash(sp)
        qApp.processEvents()  # 处理主进程事件
        app.setApplicationName(__appname__)
        # sp.close()  # 隐藏启动界面
        # w = MainWindow()
        # w.show()
        window = get_main_app(sys.argv)
        sys.exit(app.exec_())
    except Exception as e:
        print(str(e))
        logger.log(Logger.ERROR, str(e), exception=True)

if __name__ == "__main__":
    print('__main__1')
    import multiprocessing
    multiprocessing.freeze_support()
    multiprocessing.set_start_method('spawn')
    print('__main__2')
    from universal.common_parameter import MyThread
    print('__main__3')
    time1 = time.time()
    thd1 = MyThread()
    print('__main__4')
    thd1.start()
    print('get_devices is ', time.time() - time1)
    license_validator = LicenseValidator(dir_root() + os.sep +'Config/license.lic', dir_root() + os.sep +'Config/license_key.key')
    if not license_validator.is_license_valid():
        QMessageBox.critical(self, '错误', '许可证无效或已过期!程序将退出!')
        self.close()
        sys.exit(1)
    if ODModule_config.read_value('single_program', 'page') == "":
        ODModule_config.write_value('single_program','page',"0")
        normal_program()
    else:
        set_value = ODModule_config.read_value('single_program', 'page')
        if int(set_value) > 0:
            single_program()
            print('__main__5')
        else:
            normal_program()
            print('__main__6')
